package ru.ksu.ktk.diploma.sdi.mapping.resolver.impl;

import gate.util.GateException;

import java.io.IOException;
import java.util.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.hp.hpl.jena.ontology.*;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;

import ru.edu.niimm.mapping.linguistic.NLP;
import ru.ksu.ktk.diploma.sdi.mapping.Correspondence;
import ru.ksu.ktk.diploma.sdi.mapping.MappingElement;
import ru.ksu.ktk.diploma.sdi.mapping.Triple;
import ru.ksu.ktk.diploma.sdi.mapping.loaders.CrmLoader;
import ru.ksu.ktk.diploma.sdi.mapping.resolver.*;
import ru.ksu.ktk.diploma.sdi.mapping.resolver.sampling.SamplingCommand;
import ru.ksu.ktk.diploma.sdi.mapping.resolver.sampling.SamplingContext;
import ru.ksu.ktk.diploma.sdi.mapping.thesauri.ThesauriDescriptor;
import ru.ksu.ktk.diploma.sdi.mapping.thesauri.ThesauriService;
import ru.ksu.ktk.diploma.sdi.util.DescriptorsUtil;
import ru.ksu.ktk.diploma.sdi.util.OntClassUtil;

public class MappingResolverImpl implements MappingResolver {
    protected static final Log log = LogFactory.getLog(MappingResolverImpl.class);
    /**
     * CIDOC CRM ontology loader
     */
    private CrmLoader crmLoader;
    /**
     * CIDOC CRM ontology
     */
    private OntModel crmOntology;
    /**
     * thesauri service
     */
    private ThesauriService thesauriService;

    /**
     * domains
     */
    private List<OntClass> domains = new ArrayList<OntClass>();
    /**
     * triples <Domain, Property, Range>
     */
    private List<Triple> triples = new ArrayList<Triple>();
    /**
     * sampling strategy
     */
    private SamplingCommand samplingCommand;

    public List<Triple> findMapping(List<Correspondence> correspondences) {
        extractDomains(correspondences);
        buildCompleteMappingGraph();
        return triples;
    }

    public CrmLoader getCrmLoader() {
        return crmLoader;
    }

    public void setCrmLoader(CrmLoader crmLoader) {
        this.crmLoader = crmLoader;
    }

    public ThesauriService getThesauriService() {
        return thesauriService;
    }

    public void setThesauriService(ThesauriService thesauriService) {
        this.thesauriService = thesauriService;
    }

    public SamplingCommand getSamplingCommand() {
        return samplingCommand;
    }

    public void setSamplingCommand(SamplingCommand samplingCommand) {
        this.samplingCommand = samplingCommand;
    }

    protected void init() {
        this.crmOntology = crmLoader.load();
    }

    /**
     * extract domains from correspondences
     * 
     * @param correspondences
     */
    private void extractDomains(List<Correspondence> correspondences) {
        for (Correspondence corr : correspondences){
            List<MappingElement> mappingElements = sampleElements(corr);
            for (MappingElement mappingElement : mappingElements){
                String domainUri = mappingElement.getTargetTriple().getDomainUri();
                OntClass domainClass = crmOntology.getOntClass(domainUri);
                if (!domains.contains(domainClass)){
                    domains.add(domainClass);
                }
            }
        }
    }

    /**
     * sample mapping element of given correspondence
     * 
     * @param corr
     * @return mapping elements
     */
    private List<MappingElement> sampleElements(Correspondence corr) {
        SamplingContext context = new SamplingContext(corr.getMappingElements());
        samplingCommand.setContext(context);
        return samplingCommand.execute();
    }

    /**
     * build complete mapping graph as list of S-P-O triples
     * 
     * @param domains
     * @return
     */
    private void buildCompleteMappingGraph() {
        if (domains.size() > 1){
            for (int i = 0; i < domains.size(); i++){
                OntClass subject = domains.get(i);
                for (int j = i + 1; j < domains.size(); j++){
                    OntClass object = domains.get(j);
                    List<OntProperty> predicates = OntClassUtil.retrieveProperties(subject, object);
                    List<Triple> spoTriples = convertToTriples(predicates, subject, object);
                    triples.addAll(spoTriples);
                }
            }
        }

    }

    private List<Triple> convertToTriples(List<OntProperty> predicates, OntClass subject, OntClass object) {
        String thesauriLanguage = thesauriService.getThesauriLanguage();
        List<Triple> triples = new ArrayList<Triple>();
        String subjectUri = subject.getURI();
        String objectUri = object.getURI();
        for (OntProperty property : predicates){
            String propertyUri = property.getURI();
            Triple triple = new Triple(subjectUri, propertyUri, objectUri);
            String rdfsLabel = property.getLabel(thesauriLanguage);
            triple.setRdfsLabel(rdfsLabel);
            triples.add(triple);
        }
        return triples;
    }

}
